package org.jeecgframework.core.aop;

import java.io.Serializable;
import java.lang.reflect.Method;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jeecgframework.core.annotation.Ehcache;
import org.jeecgframework.core.util.LogUtil;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;

/**
 * 缓存切面  根据缓存名 缓存和清除缓存
 * 策略 1、配置缓存对象 ，EhcacheAspect和Cache.xml都要配置， 缓存名为：实体类名+"Cache"
 *     2、 增加缓存 @Ehcache(cacheName="abc")
 *     3、实体save update delete时根据cacheName清空缓存，已封装在公共Dao里
 * @author  张涛
 *
 */
@Component
@Aspect
public class EhcacheAspect {
	//定义并初始化缓存对象， 缓存名为实体类名+"Cache"，Cache.xml里的缓存名也使用这个
	public static Cache PTypeEntityCache;
	static {
		
		if (PTypeEntityCache == null) {
			PTypeEntityCache = CacheManager.getInstance().getCache("PTypeEntityCache");
		}
		
	}
	
	/**
	 * 根据缓存名  选择使用哪个缓存对象
	 * @param cacheName
	 * @return
	 */
	public static Cache getCache(String cacheName){
		if("PTypeEntityCache".equals(cacheName)){
			return PTypeEntityCache;
		}
		return null;
	}

	@Pointcut("@annotation(org.jeecgframework.core.annotation.Ehcache)")
	public void simplePointcut() {
	}

	@AfterReturning(pointcut = "simplePointcut()")
	public void simpleAdvice() {
	}

	@Around("simplePointcut()")
	public Object aroundLogCalls(ProceedingJoinPoint joinPoint)
			throws Throwable {
		String targetName = joinPoint.getTarget().getClass().toString();
		String methodName = joinPoint.getSignature().getName();
		Object[] arguments = joinPoint.getArgs();  
		
		//试图得到标注的Ehcache类
		@SuppressWarnings("unused")
		Method[] methods = joinPoint.getTarget().getClass().getMethods();
		Ehcache flag = null;
		for(Method m:methods){
			if(m.getName().equals(methodName)){
				Class[] tmpCs = m.getParameterTypes();  
                if(tmpCs.length==arguments.length){  
                	flag = m.getAnnotation(Ehcache.class);
    				break; 
            }  
			}
		}
		if(flag==null){
			return null;
		}
		//Ehcache flag =joinPoint.getTarget().getClass().getMethod(methodName).getAnnotation(Ehcache.class);
		Object result;
		String cacheKey = getCacheKey(targetName, methodName, arguments);
		LogUtil.debug("cacheKey："+cacheKey);
		LogUtil.debug("缓存的对象："+flag.cacheName());
		Element element = null;
		Cache targetCache = getCache(flag.cacheName());
		if(targetCache== null){
			return null;
		}
		
		element = targetCache.get(cacheKey);
		//未缓存  则执行方法并缓存数据
		if (element == null) {
			LogUtil.debug(flag.cacheName()+"：未缓存");
			if ((arguments != null) && (arguments.length != 0)) {
				result = joinPoint.proceed(arguments);
			} else {
				result = joinPoint.proceed();
			}

			element = new Element(cacheKey, (Serializable) result);
			
			targetCache.put(element);
			
		}
		//已缓存 则返回缓存数据
		return element.getValue();
	}
	
	/**
	 * 根据  缓存名(实体类名+"Cache")清空缓存
	 * @param targetName
	 */
	public static void removeCache(String targetName) {
		Cache targetCache = getCache(targetName);
		if(targetCache!=null){
			LogUtil.debug("清除缓存："+targetName);
		    targetCache.removeAll();
		}
	}

	/**
	 * 获得cache key的方法，cache key是Cache中一个Element的唯一标识 cache key包括
	 * 包名+类名+方法名，如com.co.cache.service.UserServiceImpl.getAllUser
	 */
	private String getCacheKey(String targetName, String methodName,
			Object[] arguments) {
		StringBuffer sb = new StringBuffer();
		sb.append(targetName).append(".").append(methodName);
		if ((arguments != null) && (arguments.length != 0)) {
			for (int i = 0; i < arguments.length; i++) {
				sb.append(".").append(JSON.toJSONString(arguments[i]));
			}
		}
		return sb.toString();
	}
}
